package cn.inyaa.admin.config;

import cn.inyaa.admin.sys.dao.InyaaSysApiDao;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import java.util.List;

/**
 * <h1>WebSecurityConfig</h1>
 * Created by hanqf on 2020/11/11 17:01.
 */

@EnableWebSecurity
@Configuration
@Slf4j
@RequiredArgsConstructor
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    private final UserDetailsService userDetailsService;
    private final AuthenticationEntryPoint authenticationEntryPoint;
    private final InyaaAccessDeniedHandler inyaaAccessDeniedHandler;
    private final InyaaSysApiDao inyaaSysApiDao;
    private final InyaaAccessDecisionManager inyaaAccessDecisionManager;
    private final InyaaFilterInvocationSecurityMetadataSource inyaaFilterInvocationSecurityMetadataSource;
    private final InyaaAuthenticationSuccessHandler inyaaAuthenticationSuccessHandler;
    private final InyaaAuthenticationFailHandler inyaaAuthenticationFailHandler;
    private final TokenFilter tokenFilter;

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        http.cors().and().csrf().disable();

        List<String> list = inyaaSysApiDao.findUrlByAllowAccess();
        String[] urls = list.toArray(new String[0]);
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.NEVER);
        http.authorizeRequests()//登录成功就可以访问
                //不需要登录就可以访问
                .mvcMatchers(urls).permitAll()
                ///所有路径都需要登录
                .anyRequest().authenticated().withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {
                    @Override
                    public <O extends FilterSecurityInterceptor> O postProcess(O o) {
                        o.setSecurityMetadataSource(inyaaFilterInvocationSecurityMetadataSource);
                        o.setAccessDecisionManager(inyaaAccessDecisionManager);
                        return o;
                    }
                });
        http.formLogin().loginProcessingUrl("/login")
                .successHandler(inyaaAuthenticationSuccessHandler)
                .failureHandler(inyaaAuthenticationFailHandler);
        http.exceptionHandling()
                //匿名用户无权限
                .authenticationEntryPoint(authenticationEntryPoint)
                //认证用户无权限
                .accessDeniedHandler(inyaaAccessDeniedHandler);
        //权限控制
        http.addFilterBefore(tokenFilter, UsernamePasswordAuthenticationFilter.class);
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
    }

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }
}
